using System;
using System.Collections.Generic;
using System.Text;
using BizTalkCop.Rules.Bases;
using Microsoft.FxCop.Sdk;
using System.Collections;
using System.Xml;

namespace BizTalkCop.Rules.Bases
{
    /// <summary>
    /// Base class for rules with configured settings
    /// </summary>
    public abstract class ConfiguredRuleBase : RuleBase, IConfigurableRule
    {

        #region Fields 

        private static Dictionary<string, Hashtable> _currentSettings;
        private static Dictionary<string, Hashtable> _defaultSettings;

        /// <summary>
        /// Cache of default configured settings
        /// </summary>
        protected Hashtable _default;

        /// <summary>
        /// Cache of current configured setttings
        /// </summary>
        protected Hashtable _current;

        #endregion

        #region Constructors

        /// <summary>
        /// Set up config setting caches for base classes
        /// </summary>
        static ConfiguredRuleBase()
        {
            _currentSettings = new Dictionary<string, Hashtable>();
            _defaultSettings = new Dictionary<string, Hashtable>();
        }

        /// <summary>
        /// Constructor with initial state
        /// </summary>
        /// <param name="name">Rule name, key for Rules.xml</param>
        protected ConfiguredRuleBase(string name) : base(name) { }

        #endregion

        #region Protected methods

        /// <summary>
        /// Sets configuration values from defaults
        /// </summary>
        /// <param name="type">Configured type</param>
        /// <param name="defaults">Default setting values</param>
        protected static void SetDefaults(Type type, Dictionary<string, string> defaults)
        {
            string typeName = type.FullName;
            _currentSettings[typeName ]= new Hashtable();
            _defaultSettings[typeName] = new Hashtable();
            foreach (KeyValuePair<string, string> defaultSetting in defaults)
            {
                _defaultSettings[typeName].Add(defaultSetting.Key, defaultSetting.Value);
            }
            ConfigurationHelper.CopyFromDefault(_defaultSettings[typeName], _currentSettings[typeName]);
        }

        /// <summary>
        /// Gets the current value for the named setting
        /// </summary>
        /// <param name="settingName">Setting name</param>
        /// <returns>Setting value</returns>
        protected string GetConfiguredSetting(string settingName)
        {
            return GetConfiguredSetting(this.GetType(), settingName);
        }

        /// <summary>
        /// Gets the current value for the named setting
        /// </summary>
        /// <param name="type">Configured type</param>
        /// <param name="settingName">Setting name</param>
        /// <returns>Setting value</returns>
        protected static string GetConfiguredSetting(Type type, string settingName)
        {
            return _currentSettings[type.FullName][settingName].ToString();
        }

        #endregion

        #region IConfigurableRule

        /// <summary>
        /// Gets the default settings
        /// </summary>
        public IDictionary DefaultSettings
        {
            get
            {
                if (_default == null)
                {
                    if (_defaultSettings.ContainsKey(this.GetType().FullName))
                    {
                        _default = _defaultSettings[this.GetType().FullName];
                    }
                    else
                    {
                        _default = new Hashtable();
                    }
                }
                return _default;
            }
        }

        /// <summary>
        /// Loads current settings from project file
        /// </summary>
        /// <param name="node"><Node to read from/param>
        public void LoadSettings(XmlNode node)
        {
            if (_currentSettings.ContainsKey(this.GetType().FullName))
            {
                ConfigurationHelper.LoadSettings(this, node);
            }
        }

        /// <summary>
        /// Saves current settings to the project file
        /// </summary>
        /// <param name="writer">Writer to save against</param>
        public void SaveSettings(XmlWriter writer)
        {
            if (_currentSettings.ContainsKey(this.GetType().FullName))
            {
                ConfigurationHelper.SaveSettings(this, writer);
            }
        }

        /// <summary>
        /// Returns the current settings
        /// </summary>
        public IDictionary Settings
        {
            get 
            {
                if (_current == null)
                {                    
                    if (_currentSettings.ContainsKey(this.GetType().FullName))
                    {
                        _current = _currentSettings[this.GetType().FullName];
                    }
                    else
                    {
                        _current = new Hashtable();
                    }
                }
                return _current;
            }
        }

        #endregion

    }
}
